`timescale 1ns/1ns

module tb_ieee754_plus();
    reg [31:0] a, b;
    reg opCode;
    wire [31:0] c;
    wire err;
    
    integer test_count = 0;
    integer pass_count = 0;
    integer fail_count = 0;
    
    // 实例化被测试模块
    ieee754_plus uut (
        .a(a),
        .b(b),
        .c(c),
        .opCode(opCode),
        .err(err)
    );
    
    // 显示浮点数信息
    task display_float;
        input [31:0] value;
        real r;
        begin
            r = $bitstoshortreal(value);
            $display("  Hex: %8h | Sign: %b | Exp: %2h | Frac: %6h | Value: %0.6f",
                     value, value[31], value[30:23], value[22:0], r);
        end
    endtask
    
    // 执行测试用例
    task run_test;
        input [31:0] expected;
        input expected_err;
        begin
            test_count = test_count + 1;
            
            #10; // 等待计算完成
            
            $display("Test %0d:", test_count);
            $display("A:"); display_float(a);
            $display("B:"); display_float(b);
            $display("Operation: %s", opCode ? "Subtract" : "Add");
            
            // 显示实际结果
            $display("Actual Result:");
            display_float(c);
            $display("Actual Error: %b", err);
            
            // 检查结果是否正确
            if (c === expected && err === expected_err) begin
                $display("EXPECTED RESULT:");
                display_float(expected);
                $display("Expected Error: %b", expected_err);
                $display(">>> TEST PASSED <<<");
                pass_count = pass_count + 1;
            end
            else begin
                $display("ERROR! Expected:");
                display_float(expected);
                $display("Expected Error: %b", expected_err);
                $display(">>> TEST FAILED <<<");
                fail_count = fail_count + 1;
            end
            $display("------------------------------------------------");
        end
    endtask
    
    // 主测试过程
    initial begin
        $display("Starting IEEE 754 FPU Test");
        $display("==========================");
        
        // 测试用例 1: 1.0 + 2.0 = 3.0
        opCode = 0; 
        a = 32'h3f800000; // 1.0
        b = 32'h40000000; // 2.0
        run_test(32'h40400000, 0); // 3.0
        
        // 测试用例 2: 5.0 - 2.5 = 2.5
        opCode = 1; 
        a = 32'h40a00000; // 5.0
        b = 32'h40200000; // 2.5
        run_test(32'h40200000, 0); // 2.5
        
        // 测试用例 3: -3.0 + 1.5 = -1.5
        opCode = 0; 
        a = 32'hc0400000; // -3.0
        b = 32'h3fc00000; // 1.5
        run_test(32'hbfc00000, 0); // -1.5
        
        // 测试用例 4: 非规格化数加法
        opCode = 0;
        a = 32'h00000001; // 最小非规格化数 ≈1.4e-45
        b = 32'h00000001;
        run_test(32'h00000002, 0); // 约2.8e-45
        
        // 测试用例 5: 下溢归零
        opCode = 1;
        a = 32'h00000001;
        b = 32'h00000002;
        run_test(32'h00000001, 0); // 负数会被归零处理，实际上因为太小可能表示为0
        
        // 测试用例 6: 等值相减
        opCode = 1;
        a = 32'h40400000; // 3.0
        b = 32'h40400000; // 3.0
        run_test(32'h00000000, 0); // 0.0
        
        // 测试用例 7: 溢出测试
        opCode = 0;
        a = 32'h7f7fffff; // 最大单精度数 ~3.4e38
        b = 32'h7f7fffff;
        run_test(32'h7f800000, 1); // 无穷大 + 错误标志
        
        // 测试用例 8: 正负零处理
        opCode = 0;
        a = 32'h00000000; // +0.0
        b = 32'h80000000; // -0.0
        run_test(32'h00000000, 0); // 0.0
        
        // 测试用例 9: 大数减小数
        opCode = 1;
        a = 32'h41200000; // 10.0
        b = 32'h40a00000; // 5.0
        run_test(32'h40a00000, 0); // 5.0
        
        // 测试用例 10: 分数运算
        opCode = 0;
        a = 32'h3eaaaaab; // 1/3 ≈0.333333
        b = 32'h3eaaaaab;
        run_test(32'h3f2aaaab, 0); // 2/3 ≈0.666666
        
        // 测试摘要
        $display("\nTEST SUMMARY:");
        $display("Tests run:    %0d", test_count);
        $display("Tests passed: %0d", pass_count);
        $display("Tests failed: %0d", fail_count);
        $display("Pass rate:    %0.1f%%", (pass_count * 100.0) / test_count);
        $display("\nSimulation finished");
        $finish;
    end
endmodule